﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using BTM_Client_Application.Chat;
using BTM_Client_Application.DeviceViewer;
using BTM_Client_Application.SupportClasses;
using BTM_Client_DBwork.Constants;
using Client_Server_Interface;
using DevicesInt;
using IDeviceInterface = Client_Server_Interface.IDeviceInterface;

namespace BTM_Client_Application
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        private DeviceWorker _dw;
        private ErrorList _errorList;
        private MapControl _map;
        //private DeviceControlWindow _deviceControlWindow;
        private DeviceControlContainer _deviceControlWindow;
        private List<IDeviceInterface> _activeDeviceList;
        //private List<TreeViewItem> _treeItemsList;
        private readonly OptionsWindow _optionsWindow = new OptionsWindow();
        private readonly AboutWindow _aboutWindow = new AboutWindow();

        private SortedList<int, string> _logTabs;
        private SortedList<int, string> _graphTabs;

        private readonly string _mapTitle = Res.Rm.GetString("Map", AliveInfo.CurrentCulture);
        private readonly string _monitoringTitle = Res.Rm.GetString("Monitoring", AliveInfo.CurrentCulture);
        private readonly string _logTitle = Res.Rm.GetString("Log", AliveInfo.CurrentCulture);

        private const double MapZoom = 7;
        private const double MapScaling = 25;
        private bool _showInfoButtonOpened;
        private bool _started;
        private bool _editState;
        private bool _useLocalMarkers = false;

        public MainWindow()
        {
            InitializeComponent();
            Icon = (BitmapImage)FindResource("MonitorToDark");
            UiLanguageChanged();
            //ShowInfoButton.Visibility = Visibility.Hidden;
            AliveInfo.MainWindow = this;
            StationElement.UseMainWindowDispatcherProperty = UseDispatcher;
            StyleProperty.OverrideMetadata(typeof(Window), new FrameworkPropertyMetadata
            {
                DefaultValue = FindResource(typeof(Window))
            });
        }

        private void ExitMenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            CloseApplication();
        }

        private void CloseApplication()
        {
            _map.DisconnectMap();
            Application.Current.Shutdown();
        }

        private void MainWindow_OnInitialized(object sender, EventArgs e)
        {
            AliveInfo.MegaDeviceTree.TreeViewItemStyle = FindResource("TreeViewItemStyle") as Style;
            _logTabs = new SortedList<int, string>();
            _graphTabs = new SortedList<int, string>();
            //SwithUp
            //AllCheck();
            InitMonitoring();
            AddLogTabItem();
            _optionsWindow.OptionsSaved += OptionsWindow_OnOptionsSaved;
        }

        private void OptionsWindow_OnOptionsSaved(SavedOptions opts)
        {
            if (opts.UseLocalMarkers != _useLocalMarkers)
            {
                _useLocalMarkers = opts.UseLocalMarkers;
                if (_map != null)
                    _map.FillStationsInfo();
            }
        }

        private void AllCheck()
        {
            try
            {
                string mapPath = AliveInfo.DBwork.GetParameterValue(OptionNames.MAP_CACHE_LOCATION);
                if (!File.Exists(mapPath + Res.DbCacheInFolderLocation))
                {
                    var res =
                        MessageBox.Show(Res.Rm.GetString("CanNotConnectToServer", AliveInfo.CurrentCulture) + ".\r\n" +
                                        Res.Rm.GetString("WouldULikeToDoItNow", AliveInfo.CurrentCulture) + '?',
                                        Res.Rm.GetString("Warning", AliveInfo.CurrentCulture), MessageBoxButton.YesNo,
                                        MessageBoxImage.Question);
                    if (res == MessageBoxResult.Yes)
                    {
                        SelectCachelocation();
                    }
                }
            }
            catch (Exception)
            {
                var res =
                    MessageBox.Show(Res.Rm.GetString("MapCacheLocationNotSet", AliveInfo.CurrentCulture) + ".\r\n" +
                                    Res.Rm.GetString("WouldULikeToDoItNow", AliveInfo.CurrentCulture) + '?',
                                    Res.Rm.GetString("Warning", AliveInfo.CurrentCulture), MessageBoxButton.YesNo,
                                    MessageBoxImage.Question);
                if (res == MessageBoxResult.Yes)
                {
                    SelectCachelocation();
                }
            }
        }

        private void SelectCachelocation()
        {
            var d = new MyOpenFileDialog();
            try
            {
                var fname = d.Show();
                var fi = new FileInfo(fname);
                var rightDir = fi.Directory.Parent.Parent.FullName;
                AliveInfo.DBwork.SetParameter(OptionNames.MAP_CACHE_LOCATION, rightDir);
            }
            catch (IncorrectInputValueException)
            {
            }
        }

        private void InitMonitoring()
        {

            _dw = new DeviceWorker();
            AliveInfo.DeviceWorker = _dw;

            AliveInfo.ChangeDeviceOpenedState = _dw.ChangeDeviceOpenedState;
            AliveInfo.StatusUpdateEvent += status =>
            {
                StatusBox.Text = Res.Rm.GetString(status, AliveInfo.CurrentCulture);
            };
            AliveInfo.UnreadRecordsCountChangedEvent += count =>
            {
                UnreadRecordsCountBox.Text = count.ToString(CultureInfo.InvariantCulture);
            };
            AliveInfo.ServerDisconnectEvent += () =>
            {
                AliveInfo.ClientHelper.Disconnect();
                LoadingWindow.CloseWindow();
                MessageBox.Show("Соединение с сервером потеряно. Работа программы завершена.");
                Application.Current.Dispatcher.InvokeShutdown();
                //Application.Current.Shutdown();
            };

            AliveInfo.CreateEventControl(ShowInfoButton);
            
            //var sts = _map.Stations;

            _activeDeviceList = DeviceWorker.CreateDeviceList(AliveInfo.DeviceTree);
            AliveInfo.MegaDeviceTree.DeviceTree = AliveInfo.DeviceTree;
            AliveInfo.MegaDeviceTree.Devices = _activeDeviceList;
            //Медленно здесь!
            var dt1 = DateTime.Now;
            AliveInfo.MegaDeviceTree.SetStations(MapZoom, MapScaling);
            var dt2 = DateTime.Now;
            var tp = dt2 - dt1;

            AliveInfo.MegaDeviceTree.SetDevices();

            //CreateDeviceTreeView();
            RestartMonitoring();

            var tip = new ToolTip();
            tip.Opened += (o, args) =>
            {
                if (!AliveInfo.StatusList.Any())
                {
                    tip.Content = Res.Rm.GetString("Ok", AliveInfo.CurrentCulture);
                    return;
                }
                foreach (var stat in AliveInfo.StatusList)
                {
                    tip.Content += " " + Res.Rm.GetString(stat, AliveInfo.CurrentCulture) + ";";
                }
            };
            StatusBox.ToolTip = tip;
            AliveInfo.AddStatus("Ok");

            _errorList = new ErrorList();
            _map = new MapControl(MapZoom, MapScaling);
            AliveInfo.SetMapPosition = _map.CenterPosition;
            SetErrorListTabContent();
            SetMapTabContent();

            //Chat
            AliveInfo.Chat = new ChatClient(AliveInfo.Login);
            ChatContent.Children.Clear();
            try
            {
                ChatContent.Children.Add(new ChatControl());
            }
            catch (Exception ex)
            {
                AliveInfo.ClientEvents.AddEvent(Res.Rm.GetString("ChatError", AliveInfo.CurrentCulture), ex.Message);
                ChatTab.IsEnabled = false;
            }

            TabsContainer.SelectionChanged += (sender1, args) =>
            {
                var cont = sender1 as TabControl;
                //ErrorList
                _dw.AllOpenedDevicesState = Equals(cont.SelectedItem, ErrorListTab);
                //Chat
                ChatControl chat;
                try
                {
                    chat = ChatContent.Children[0] as ChatControl;
                    chat.UnreadMessage += ChatOnUnreadMessage;
                }
                catch (Exception)
                {
                    return;
                }
                
                if (Equals(cont.SelectedItem, ChatTab))
                {
                    chat.IsThisVisible = true;
                }
                else
                {
                    chat.IsThisVisible = false;
                }
            };
        }

        private void ChatOnUnreadMessage(int i)
        {
            SoundsWorker.NewChatMessagePlay();
        }

        private void DeviceControlWindowOnClosed(object sender, EventArgs eventArgs)
        {
            _deviceControlWindow = null;
        }

        private void StartMonitoring()
        {
            string statusRequestPeriod;
            try
            {
                statusRequestPeriod = AliveInfo.DBwork.GetParameterValue(OptionNames.STATUS_REQUEST_PERIOD);
            }
            catch (Exception)
            {
                AliveInfo.DBwork.SetParameter(OptionNames.STATUS_REQUEST_PERIOD, OptionDefaultValue.STATUS_REQUEST_PERIOD);
                statusRequestPeriod = OptionDefaultValue.STATUS_REQUEST_PERIOD;
            }
            //_activeDeviceList = DeviceWorker.CreateDeviceList(AliveInfo.DeviceTree);
            //FillDeviceTreeView(_activeDeviceList);
            DeviceTreeView.ItemsSource = AliveInfo.MegaDeviceTree.GetTreeViewItemsSource();
            _dw.Initialize(_activeDeviceList, NewErrorRecordReaction, statusRequestPeriod);
            _dw.Start();
            _started = true;
        }

        private void StopMonitoring()
        {
            if (!_started)
                return;
            _dw.Stop();
            _activeDeviceList = null;
            _errorList.Clear();
            _started = false;
        }

        private void NewErrorRecordReaction(DeviceTreeItem.DeviceInfo device, ObservableCollection<ErrorListRecord> newRecords, int unreadCount, int totalUnreadCount)
        {
            try
            {
                Dispatcher.Invoke(new VoidDelegate(() =>
                {
                    if (device != null)
                        _errorList.UpdateErrorRecords(newRecords);
                    AliveInfo.UnreadRecordsCount = totalUnreadCount;
                    RecordsCountBox.Text = _errorList.RecordsCount.ToString(CultureInfo.InvariantCulture);
                }));
            }
            catch (Exception)                                                           //WTF?!?!?!?!
            {

            }
            
        }

        private void RestartMenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            StopMonitoring();
            InitMonitoring();
        }

        private void RestartMonitoring()
        {
            //StopMonitoring();
            try
            {
                StartMonitoring();
            }
            catch (ClientException ex)
            {
                AliveInfo.ClientEvents.AddEvent("Ошибка инициализации устройств", ex.Message);
                return;
            }
        }

        private void Open_OnClick(object sender, RoutedEventArgs e)
        {
            _dw.AllOpenedDevicesState = true;
        }

        private void Close_OnClick(object sender, RoutedEventArgs e)
        {
            _dw.AllOpenedDevicesState = false;
        }

        public void OpenDevice(DeviceInfoControl info)
        {
            if (!PermissionsHelper.CheckPermission(AliveInfo.ClientHelper.Permissions, PermissionTypes.EditDeviceOptions))
            {
                MessageBox.Show(Res.Rm.GetString("NotEnoughRights"), Res.Rm.GetString("Info"), MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }
            if (info != null)
            {
                //ToImplement
                //Что-нить делаем с устройством

                var inf = info.DevInfo;
                DeviceControl control;
                try
                {
                    control = DeviceWorker.GetControl(inf.LibraryName, inf.IpAddress);
                }
                catch (ClientException ex)
                {
                    MessageBox.Show(ex.Message + Environment.NewLine + ex.AdditionalInfo,
                                    Res.Rm.GetString("Warning"));
                    return;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, Res.Rm.GetString("Warning"));
                    return;
                }

                switch (control.GetControlType)
                {
                    //Ссылка
                    case DeviceControl.ControlType.NetworkLink:
                        var br = new BrowserWindow();
                        br.NavigateTo((string)control.GetControl(), info.DevInfo.Title + " - " + info.DevInfo.ParentInfo.Station);
                        br.Show();
                        break;
                    //Окно
                    case DeviceControl.ControlType.Window:
                        break;
                    //Список параметров
                    case DeviceControl.ControlType.ParametersList:
                        break;
                    //Элемент упавления WPF
                    case DeviceControl.ControlType.Control:
                        if (_deviceControlWindow == null)
                        {
                            _deviceControlWindow = new DeviceControlContainer();
                            _deviceControlWindow.Closed += DeviceControlWindowOnClosed;
                        }
                        var c = (UserControl)control.GetControl(AliveInfo.CurrentCulture);
                        _deviceControlWindow.AddDevice(inf.Title, inf.ParentInfo.Station, c);
                        _deviceControlWindow.Show();
                        break;
                    default:
                        return;
                }
            }
        }

        private void DeviceTreeView_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            //if (!PermissionsHelper.CheckPermission(AliveInfo.ClientHelper.Permissions, PermissionTypes.EditDeviceOptions))
            //    return;
            var tree = (TreeView) sender;
            if (tree.SelectedItem == null)
                return;
            var info = (((TreeViewItem)tree.SelectedItem).Tag as DeviceInfoControl);
            OpenDevice(info);
        }

        private void SetErrorListTabContent()
        {
            //Content.Children.Add(_errorList);
            ErrorListTab.Header = _monitoringTitle;
            ListContent.Children.Add(_errorList);
            //_dw.AllOpenedDevicesState = true;
        }

        private void SetMapTabContent()
        {
            MapTab.Header = _mapTitle;
            MapContent.Children.Add(_map);
        }

        private void ShowInfoButton_OnClick(object sender, RoutedEventArgs e)
        {
            ChangeShowInfoButtonState();
        }

        private void ChangeShowInfoButtonState(bool? open = null)
        {
            if (open != null)
                _showInfoButtonOpened = (bool)open;
            if (!_showInfoButtonOpened)
            {
                //При открытии
                var im = new Image {Source = FindResource("NavigateNextImageDark") as BitmapImage};
                ShowInfoButton.Content = im;
                ClientEventsContainer.Children.Add(AliveInfo.ClientEvents);
            }                
            else
            {
                //При закрытии
                var im = new Image { Source = FindResource("NavigatePreviousImageDark") as BitmapImage };
                ShowInfoButton.Content = im;
                if(ShowInfoButton.Tag != null)
                    if ((bool) ShowInfoButton.Tag)
                    {
                        ShowInfoButton.Visibility = Visibility.Hidden;
                    }
                ClientEventsContainer.Children.Clear();
            }
            _showInfoButtonOpened = !_showInfoButtonOpened;
        }

        private void UiLanguageChanged()
        {
            //Assembly info
            Assembly assembly = Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
            Title = fvi.ProductName + " v. " + fvi.ProductVersion;
            //Title = Res.Rm.GetString("MonitoringSystem", AliveInfo.CurrentCulture);
            ChatTab.Header = Res.Rm.GetString("Chat", AliveInfo.CurrentCulture);
            //RecordsCountBox.Text = Res.Rm.GetString("RecordsCount", AliveInfo.CurrentCulture);
            //UnreadRecordsCountBox.Text = Res.Rm.GetString("UnreadRecordsCount", AliveInfo.CurrentCulture);
            //Menu
            EditMenuItem.Header = Res.Rm.GetString("MoveMarkers", AliveInfo.CurrentCulture);
            ExitMenuItem.Header = Res.Rm.GetString("Exit", AliveInfo.CurrentCulture);
            MenuMenuItem.Header = Res.Rm.GetString("Menu", AliveInfo.CurrentCulture);
            OptionsMenuItem.Header = Res.Rm.GetString("Parameters", AliveInfo.CurrentCulture);
            AboutMenuItem.Header = Res.Rm.GetString("AboutProgram", AliveInfo.CurrentCulture);
            //Status panel
            RecordsCountLabel.Text = Res.Rm.GetString("RecordsCount", AliveInfo.CurrentCulture);
            UnreadRecordsCountLabel.Text = Res.Rm.GetString("UnreadRecordsCount", AliveInfo.CurrentCulture);
            _map.UpdateUiLanguage();
        }

        public void UseDispatcher(VoidDelegate del)
        {
            Dispatcher.Invoke(new Action(() => del()));
        }

        private void EditMenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            var item = sender as MenuItem;
            _map.AllowEditMarkers = _editState = !_editState;
            //_map.AllowEditMarkers = false;
            if (_editState)
            {
                item.Header = Res.Rm.GetString("EndMoveMarkers", AliveInfo.CurrentCulture);
            }
            else
            {
                item.Header = Res.Rm.GetString("MoveMarkers", AliveInfo.CurrentCulture);
            }
        }

        private void FilterButton_OnClick(object sender, RoutedEventArgs e)
        {
            SelectTabByName(_monitoringTitle);
            //var w = new MyWindow();
            //w.Content = new RealTimeFilterControl(new ErrorList.ErrorListRecordImpl());
            //w.Show();
        }

        private void AddLogTabItem()
        {
            var item = new TabItem();
            var control = new LogControl();
            item.Content = control;
            item.Header = control.Title;
            TabsContainer.Items.Add(item);
        }

        private void SelectTabByName(string tabHeader)
        {
            foreach (TabItem item in TabsContainer.Items)
            {
                if ((string) item.Header == tabHeader)
                {
                    item.IsSelected = true;
                    return;
                }
            }
        }

        public enum TabType
        {
            Graph,
            Log
        }

        public void AppendTab()
        {
            
        }

        //ToImprove
        /*public void AppendGraphTab(TabType type, UIElement content)
        {
            string title;
            try
            {
                var value = _graphTabs.Last();
                title = Res.Rm.GetString("Graph") + '_' + (value.Key + 1);
                _graphTabs.Add(value.Key + 1, title);
            }
            catch (Exception)
            {
                title = Res.Rm.GetString("Graph") + '_' + 0;
                _graphTabs.Add(0, title);
            }
            var item = new TabItem { Content = content, Header = title };
            item.MouseDoubleClick += ItemOnMouseDoubleClick;
            TabsContainer.Items.Add(item);
            SelectTabByName(title);
        }*/

        //ToImprove
        public void AppendTab(TabType type, UIElement content)
        {
            string gt;
            SortedList<int, string> tabs;
            switch (type)
            {
                case TabType.Graph:
                    gt = Res.Rm.GetString("Graph", AliveInfo.CurrentCulture);
                    tabs = _graphTabs;
                    break;
                case TabType.Log:
                    gt = Res.Rm.GetString("Selection", AliveInfo.CurrentCulture);
                    tabs = _logTabs;
                    break;
                default:
                    throw new ArgumentOutOfRangeException("type");
            }
            string title = gt + '_';
            try
            {
                var value = tabs.Last();
                title += (value.Key + 1);
                tabs.Add(value.Key + 1, title);
            }
            catch (Exception)
            {
                title += 1;
                tabs.Add(1, title);
            }
            
            var item = new TabItem {Content = content, Header = title};
            item.MouseDoubleClick+= ItemOnMouseDoubleClick;
            TabsContainer.Items.Add(item);
            SelectTabByName(title);
        }

        private void ItemOnMouseDoubleClick(object sender, MouseButtonEventArgs mouseButtonEventArgs)
        {
            var tabItem = (sender as TabItem);
            var mo = (tabItem.Content as UIElement).IsMouseOver;
            if (!mo)
                RemoveTab(sender as TabItem);
        }

        private void RemoveTab(TabItem tab)
        {
            RemoveTabByName(tab.Header.ToString());
        }

        public void RemoveTabByName(string tabHeader)
        {
            int i = -1;
            foreach (TabItem item in TabsContainer.Items)
            {
                ++i;
                if ((string) item.Header == tabHeader)
                {
                    try
                    {
                        int k = _logTabs.Single(x => x.Value == tabHeader).Key;
                        _logTabs.Remove(k);
                        break;
                    }
                    catch (Exception)
                    {
                    }

                    try
                    {
                        int k = _graphTabs.Single(x => x.Value == tabHeader).Key;
                        _graphTabs.Remove(k);
                        break;
                    }
                    catch (Exception)
                    {
                    }
                }
            }
            if(i != -1)
                TabsContainer.Items.RemoveAt(i);
        }

        private void LogButton_OnClick(object sender, RoutedEventArgs e)
        {
            SelectTabByName(_logTitle);
            /*TabItem item = new TabItem();
            var control = new LogControl();
            item.Content = control;
            item.Header = control.Title;
            TabsContainer.Items.Add(item);*/
        }

        private void MainWindow_OnClosing(object sender, CancelEventArgs e)
        {
            CloseApplication();
        }

        private void MapButton_OnClick(object sender, RoutedEventArgs e)
        {
            SelectTabByName(_mapTitle);
        }

        //ToImplement
        private void ChatButton_OnClick(object sender, RoutedEventArgs e)
        {

        }

        void OpenOptions()
        {
            _optionsWindow.Show();
            _optionsWindow.Activate();
        }

        private void OptionsMenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            OpenOptions();
        }

        private void AboutMenuItem_OnClick(object sender, RoutedEventArgs e)
        {
            _aboutWindow.Show();
            _aboutWindow.Activate();
            
        }
    }

    public delegate void UseDispatcherDelegate(VoidDelegate del);
}
